#ifndef POOL_TBS_CPP
#define POOL_TBS_CPP

#include <base/base.hpp>
#include <base/log.hpp>
#include <base/loggers/BuiltInLogger.h>
#include <condition_variable>
#include <deque>
#include <memory>
#include <mutex>

template<typename Type> class Pool {
public:
  /**
   * 重置函数
   */
  using reset_func = std::function<Type *(Type *)>;

  using self_type = Pool<Type>;

  using u_ptr = std::unique_ptr<Type>;

  /**
   * 示例重置函数
   * @param old 原本的数据指针
   * @return 新的数据指针
   */
  static Type *remake_on_release(Type *old);

  /**
   *
   * @param pool_size 池大小
   * @param resetFunc 重置函数
   */
  explicit Pool(std::size_t pool_size = 10, reset_func resetFunc = nullptr) : _rf(resetFunc), pool_size_(pool_size) {
	for (std::size_t i = 0; i < pool_size_; ++i) {
	  _data.push_back(u_ptr(new Type()));
	}
  }

  /**
   * 是否在释放时重置
   * @return
   */
  bool is_reset_on_release();

  /**
   * 设置重置函数
   * @param f
   */
  void setResetFunction(reset_func f);

  /**
   * 提取一个元素
   * @return
   */
  tbs::WrappedGuard<Type> acquire();

  /**
   * 释放获取到的元素，必须是acquire的，无需手动释放，guard会离开作用域的时候自动释放
   * @param item
   */
  void release(Type &item);

  size_t size() CONST;

protected:
  virtual void reject(tbs::sys_unique_lock &lock);

  virtual void onRelease(Type *item, tbs::sys_unique_lock &lock);

private:
  /**
   * 池包装器
   */
  class PoolWrapper : public tbs::Wrapper<Type> {
  public:
	PoolWrapper(self_type *s, Type *val) : _source(s), item(val) {}

	Type &value() override;

  protected:
	void m_release() override;

  private:
	self_type *_source;
	Type *item;
  };

  std::size_t pool_size_;
  reset_func _rf = nullptr;
  std::deque<u_ptr> _data;
  std::mutex mutex_;
  std::condition_variable condition_variable_;
};

template<typename T> class ClosedPool {
public:
  void cut_back(const size_t &s) noexcept;

  void put(T &&val) noexcept;

  /**
   * @brief 取池中一个空闲元素调用
   * @tparam ARGS 额外的参数
   * @tparam F 调用方法 首参数是T& 剩下的是ARGS
   * @param f 运行的方法
   * @param args 具体的参数
   */
  template<typename... ARGS, typename F> void work_on(F &&f, ARGS... args) noexcept;

  virtual ~ClosedPool();

  size_t size() const noexcept;

  size_t in_used() const noexcept;

private:
  using uptr = std::unique_ptr<T>;
  std::deque<uptr> _q;
  std::atomic_ulong _in_used_num{0};
  std::mutex _mutex;
  std::condition_variable condition_variable_;
};

#include <inls/base/pool.cuh>
#endif
